home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene 96
/
Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso
/
misc
/
coding
/
cp2dekit
/
samples
/
xmplay.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1996-12-29
|
47KB
|
1,882 lines
//***************************************************************************
//
// this file is (c) '94-'96 Niklas Beisert
//
// this file is part of the cubic player development kit.
// you may only use/modify/spread this file under the terms stated
// in the cubic player development kit accompanying documentation.
//
//***************************************************************************
//[filetype 0]
// color=1
// name=MOD
// interface=_plCubicPlayer
// pllink=playxm
// player=_xmpPlayer
//[filetype 10]
// color=3
// name=XM
// interface=_plCubicPlayer
// pllink=playxm
// player=_xmpPlayer
// wavetable device example
// future enhancements
// channel mapper
#include <string.h>
#include "mcp.h"
#include "binfile.h"
#include "gmdinst.h"
#include "xmplay.h"
#include "err.h"
struct channel
{
int chVol;
int chFinalVol;
int chPan;
int chFinalPan;
long chPitch;
long chFinalPitch;
unsigned char chCurIns;
int chCurNormNote;
unsigned char chSustain;
unsigned short chFadeVol;
unsigned short chAVibPos;
unsigned long chAVibSwpPos;
unsigned long chVolEnvPos;
unsigned long chPanEnvPos;
unsigned char chDefVol;
int chDefPan;
unsigned char chCommand;
unsigned char chVCommand;
long chPortaToPitch;
long chPortaToVal;
unsigned char chVolSlideVal;
unsigned char chGVolSlideVal;
unsigned char chVVolPanSlideVal;
unsigned char chPanSlideVal;
unsigned char chFineVolSlideUVal;
unsigned char chFineVolSlideDVal;
long chPortaUVal;
long chPortaDVal;
unsigned char chFinePortaUVal;
unsigned char chFinePortaDVal;
unsigned char chXFinePortaUVal;
unsigned char chXFinePortaDVal;
unsigned char chVibRate;
unsigned char chVibPos;
unsigned char chVibType;
unsigned char chVibDep;
unsigned char chTremRate;
unsigned char chTremPos;
unsigned char chTremType;
unsigned char chTremDep;
unsigned char chPatLoopCount;
unsigned char chPatLoopStart;
unsigned char chArpPos;
unsigned char chArpNotes[3];
unsigned char chActionTick;
unsigned char chMRetrigPos;
unsigned char chMRetrigLen;
unsigned char chMRetrigAct;
unsigned char chDelayNote;
unsigned char chOffset;
unsigned char chGlissando;
unsigned char chTremorPos;
unsigned char chTremorLen;
unsigned char chTremorOff;
int nextstop;
int nextsamp;
int nextpos;
sample *cursamp;
};
static int looping;
static int looped;
static int usersetpos;
static channel channels[32];
static unsigned char mutech[32];
static unsigned char globalvol;
static unsigned char curtick;
static unsigned char curtempo;
static unsigned char tick0;
static int currow;
static unsigned char (*patptr)[5];
static int patlen;
static int curord;
static int nord;
static int ninst;
static int nsamp;
static int linearfreq;
static int nchan;
static int loopord;
static int nenv;
static instrument *instruments;
static sample *samples;
static envelope *envelopes;
static unsigned char (**patterns)[5];
static unsigned short *orders;
static unsigned short *patlens;
static int jumptoord;
static int jumptorow;
static int patdelay;
static unsigned char procnot;
static unsigned char procins;
static unsigned char procvol;
static unsigned char proccmd;
static unsigned char procdat;
static unsigned char notedelayed;
static int firstspeed;
static short sintab[256]=
{
0, 50, 100, 151, 201, 251, 301, 350,
400, 449, 498, 546, 595, 642, 690, 737,
784, 830, 876, 921, 965, 1009, 1053, 1096,
1138, 1179, 1220, 1260, 1299, 1338, 1375, 1412,
1448, 1483, 1517, 1551, 1583, 1615, 1645, 1674,
1703, 1730, 1757, 1782, 1806, 1829, 1851, 1872,
1892, 1911, 1928, 1945, 1960, 1974, 1987, 1998,
2009, 2018, 2026, 2033, 2038, 2042, 2046, 2047,
2048, 2047, 2046, 2042, 2038, 2033, 2026, 2018,
2009, 1998, 1987, 1974, 1960, 1945, 1928, 1911,
1892, 1872, 1851, 1829, 1806, 1782, 1757, 1730,
1703, 1674, 1645, 1615, 1583, 1551, 1517, 1483,
1448, 1412, 1375, 1338, 1299, 1260, 1220, 1179,
1138, 1096, 1053, 1009, 965, 921, 876, 830,
784, 737, 690, 642, 595, 546, 498, 449,
400, 350, 301, 251, 201, 151, 100, 50,
0, -50, -100, -151, -201, -251, -301, -350,
-400, -449, -498, -546, -595, -642, -690, -737,
-784, -830, -876, -921, -965, -1009, -1053, -1096,
-1138, -1179, -1220, -1260, -1299, -1338, -1375, -1412,
-1448, -1483, -1517, -1551, -1583, -1615, -1645, -1674,
-1703, -1730, -1757, -1782, -1806, -1829, -1851, -1872,
-1892, -1911, -1928, -1945, -1960, -1974, -1987, -1998,
-2009, -2018, -2026, -2033, -2038, -2042, -2046, -2047,
-2048, -2047, -2046, -2042, -2038, -2033, -2026, -2018,
-2009, -1998, -1987, -1974, -1960, -1945, -1928, -1911,
-1892, -1872, -1851, -1829, -1806, -1782, -1757, -1730,
-1703, -1674, -1645, -1615, -1583, -1551, -1517, -1483,
-1448, -1412, -1375, -1338, -1299, -1260, -1220, -1179,
-1138, -1096, -1053, -1009, -965, -921, -876, -830,
-784, -737, -690, -642, -595, -546, -498, -449,
-400, -350, -301, -251, -201, -151, -100, -50
};
static int freqrange(int x)
{
if (linearfreq)
return (x<-72*256)?-72*256:(x>96*256)?96*256:x;
else
return (x<107)?107:(x>438272)?438272:x;
}
static int volrange(int x)
{
return (x<0)?0:(x>0x40)?0x40:x;
}
static int panrange(int x)
{
return (x<0)?0:(x>0xFF)?0xFF:x;
}
static void PlayNote(channel &ch)
{
int portatmp=0;
if (procins>ninst)
procins=0;
if (proccmd==3)
portatmp=1;
if (proccmd==5)
portatmp=1;
if (procvol>=0xF0)
portatmp=1;
int keyoff=0;
if (procnot==97)
{
procnot=0;
keyoff=1;
}
if ((proccmd==20)&&!procdat)
keyoff=1;
if (procins&&(procins<=ninst))
ch.chCurIns=procins;
if (!ch.chCurIns)
return;
if (procnot)
{
if (procins!=0)
ch.chSustain=1;
ch.chDelayNote=procnot;
if (proccmd==49)
{
if (procdat!=0)
return;
}
procnot--;
if (!portatmp)
{
ch.nextstop=1;
instrument &ins=instruments[ch.chCurIns-1];
if (instruments[ch.chCurIns-1].samples[procnot]>nsamp)
return;
ch.cursamp=&samples[instruments[ch.chCurIns-1].samples[procnot]];
ch.nextsamp=ch.cursamp->handle;
if (procins)
{
ch.chDefVol=(ch.cursamp->stdvol+1)>>2;
ch.chDefPan=ch.cursamp->stdpan;
}
ch.chCurNormNote=ch.cursamp->normnote;
int frq=48*256-((procnot<<8)-ch.chCurNormNote);
if (!linearfreq)
frq=mcpGetFreq6848(frq);
ch.chPitch=frq;
ch.chFinalPitch=frq;
ch.chPortaToPitch=frq;
ch.nextpos=0;
if (proccmd==9)
{
if (procdat!=0)
ch.chOffset=procdat;
ch.nextpos=ch.chOffset<<8;
}
ch.chVibPos=0;
ch.chTremPos=0;
ch.chArpPos=0;
ch.chMRetrigPos=0;
ch.chTremorPos=0;
}
else
{
int frq=48*256-((procnot<<8)-ch.chCurNormNote);
if (!linearfreq)
frq=mcpGetFreq6848(frq);
ch.chPortaToPitch=frq;
}
}
if (keyoff&&ch.cursamp)
{
ch.chSustain=0;
if ((ch.cursamp->volenv>=nenv)&&!procins)
ch.chFadeVol=0;
}
if (!ch.chSustain)
return;
if (!procins)
return;
if (!notedelayed)
{
ch.chVol=ch.chDefVol;
ch.chFinalVol=ch.chDefVol;
if (ch.chDefPan!=-1)
{
ch.chPan=ch.chDefPan;
ch.chFinalPan=ch.chDefPan;
}
}
ch.chFadeVol=0x8000;
ch.chAVibPos=0;
ch.chAVibSwpPos=0;
ch.chVolEnvPos=0;
ch.chPanEnvPos=0;
}
static unsigned short notetab[16]={32768,30929,29193,27554,26008,24548,23170,21870,20643,19484,18390,17358,16384,15464,14596,13777};
static void xmpPlayTick()
{
if (firstspeed)
{
mcpSet(-1, mcpGSpeed, firstspeed);
firstspeed=0;
}
tick0=0;
int i;
for (i=0; i<nchan; i++)
{
channel &ch=channels[i];
ch.chFinalVol=ch.chVol;
ch.chFinalPan=ch.chPan;
ch.chFinalPitch=ch.chPitch;
ch.nextstop=0;
ch.nextsamp=-1;
ch.nextpos=-1;
}
curtick++;
if (curtick>=curtempo)
curtick=0;
if (!curtick&&patdelay)
{
if (jumptoord!=-1)
{
if (jumptoord!=curord)
for (i=0; i<nchan; i++)
{
channel &ch=channels[i];
ch.chPatLoopCount=0;
ch.chPatLoopStart=0;
}
if (jumptoord>=nord)
jumptoord=loopord;
if ((jumptoord<curord)&&!usersetpos)
looped=1;
usersetpos=0;
curord=jumptoord;
currow=jumptorow;
jumptoord=-1;
patlen=patlens[orders[curord]];
patptr=patterns[orders[curord]];
}
}
if (!curtick&&patdelay)
{
patdelay--;
}
else
if (!curtick)
{
tick0=1;
currow++;
if ((jumptoord==-1)&&(currow>=patlen))
{
jumptoord=curord+1;
jumptorow=0;
}
if (jumptoord!=-1)
{
if (jumptoord!=curord)
for (i=0; i<nchan; i++)
{
channel &ch=channels[i];
ch.chPatLoopCount=0;
ch.chPatLoopStart=0;
}
if (jumptoord>=nord)
jumptoord=loopord;
if ((jumptoord<curord)&&!usersetpos)
looped=1;
usersetpos=0;
curord=jumptoord;
currow=jumptorow;
jumptoord=-1;
patlen=patlens[orders[curord]];
patptr=patterns[orders[curord]];
}
for (i=0; i<nchan; i++)
{
channel &ch=channels[i];
procnot=patptr[nchan*currow+i][0];
procins=patptr[nchan*currow+i][1];
procvol=patptr[nchan*currow+i][2];
proccmd=patptr[nchan*currow+i][3];
procdat=patptr[nchan*currow+i][4];
notedelayed=0;
PlayNote(ch);
ch.chVCommand=procvol>>4;
procvol&=0xF;
switch (ch.chVCommand)
{
case 1: case 2: case 3: case 4:
ch.chFinalVol=ch.chVol=procvol+ch.chVCommand*0x10-0x10;
break;
case 5:
ch.chFinalVol=ch.chVol=0x40;
break;
case 6: case 7: case 13: case 14:
ch.chVVolPanSlideVal=procvol;
break;
case 8:
ch.chVol-=procvol;
ch.chFinalVol=ch.chVol=volrange(ch.chVol);
break;
case 9:
ch.chVol+=procvol;
ch.chFinalVol=ch.chVol=volrange(ch.chVol);
break;
case 10:
if (procvol)
ch.chVibRate=(procvol<<2);
break;
case 11:
if (procvol)
ch.chVibDep=(procvol<<2);
break;
case 12:
ch.chFinalPan=ch.chPan=procvol*0x11;
break;
case 15:
if (procvol)
ch.chPortaToVal=procvol<<8;
break;
}
ch.chCommand=proccmd;
switch (ch.chCommand)
{
case 0:
if (procdat)
ch.chCommand=0xFF;
ch.chArpNotes[0]=0;
ch.chArpNotes[1]=procdat>>4;
ch.chArpNotes[2]=procdat&0xF;
break;
case 1:
if (procdat)
ch.chPortaUVal=procdat<<4;
break;
case 2:
if (procdat)
ch.chPortaDVal=procdat<<4;
break;
case 3:
if (procdat)
ch.chPortaToVal=procdat<<4;
break;
case 4:
if (procdat&0xF)
ch.chVibDep=(procdat&0xF)<<2;
if (procdat&0xF0)
ch.chVibRate=(procdat>>4)<<2;
break;
case 5: case 6: case 10:
if (procdat)
ch.chVolSlideVal=procdat;
break;
case 7:
if (procdat&0xF)
ch.chTremDep=(procdat&0xF)<<2;
if (procdat&0xF0)
ch.chTremRate=(procdat>>4)<<2;
break;
case 8:
ch.chFinalPan=ch.chPan=procdat;
break;
case 11:
jumptoord=procdat;
jumptorow=0;
break;
case 12:
ch.chFinalVol=ch.chVol=volrange(procdat);
break;
case 13:
if (jumptoord==-1)
jumptoord=curord+1;
jumptorow=(procdat&0xF)+(procdat>>4)*10;
break;
case 15:
if (!procdat)
{
jumptoord=procdat;
jumptorow=0;
break;
}
if (procdat>=0x20)
mcpSet(-1, mcpGSpeed, 256*2*procdat/5);
else
curtempo=procdat;
break;
case 16:
globalvol=volrange(procdat);
break;
case 17:
if (procdat)
ch.chGVolSlideVal=procdat;
break;
case 20: case 45: case 48: case 49:
ch.chActionTick=procdat;
break;
case 21:
ch.chVolEnvPos=ch.chPanEnvPos=procdat;
if (ch.cursamp->volenv<nenv)
if (ch.chVolEnvPos>envelopes[ch.cursamp->volenv].len)
ch.chVolEnvPos=envelopes[ch.cursamp->volenv].len;
if (ch.cursamp->panenv<nenv)
if (ch.chPanEnvPos>envelopes[ch.cursamp->panenv].len)
ch.chPanEnvPos=envelopes[ch.cursamp->panenv].len;
break;
case 25:
if (procdat)
ch.chPanSlideVal=procdat;
break;
case 27:
if (procdat)
{
ch.chMRetrigLen=procdat&0xF;
ch.chMRetrigAct=procdat>>4;
ch.chMRetrigPos=0;
}
break;
case 29:
if (procdat)
{
ch.chTremorLen=(procdat&0xF)+(procdat>>4)+2;
ch.chTremorOff=(procdat>>4)+1;
ch.chTremorPos=0;
}
break;
case 33:
if ((procdat>>4)==1)
{
if (procdat&0xF)
ch.chXFinePortaUVal=procdat&0xF;
ch.chFinalPitch=ch.chPitch=freqrange(ch.chPitch-(ch.chXFinePortaUVal<<2));
}
else
if ((procdat>>4)==2)
{
if (procdat&0xF)
ch.chXFinePortaDVal=procdat&0xF;
ch.chFinalPitch=ch.chPitch=freqrange(ch.chPitch+(ch.chXFinePortaDVal<<2));
}
break;
case 37:
if (procdat)
ch.chFinePortaUVal=procdat;
ch.chFinalPitch=ch.chPitch=freqrange(ch.chPitch-(ch.chFinePortaUVal<<4));
break;
case 38:
if (procdat)
ch.chFinePortaDVal=procdat;
ch.chFinalPitch=ch.chPitch=freqrange(ch.chPitch-(ch.chFinePortaDVal<<4));
break;
case 39:
ch.chGlissando=procdat;
break;
case 40:
ch.chVibType=procdat&3;
break;
case 42:
if (procdat)
ch.chPatLoopStart=currow;
else
{
ch.chPatLoopCount++;
if (ch.chPatLoopCount<=procdat)
{
jumptorow=ch.chPatLoopStart;
jumptoord=curord;
}
else
{
ch.chPatLoopCount=0;
ch.chPatLoopStart=currow+1;
}
}
break;
case 43:
ch.chTremType=procdat&3;
break;
case 44:
ch.chFinalPan=ch.chPan=procdat*0x11;
break;
case 46:
if (procdat)
ch.chFineVolSlideUVal=procdat;
ch.chFinalVol=ch.chVol=volrange(ch.chVol+ch.chFineVolSlideUVal);
break;
case 47:
if (procdat)
ch.chFineVolSlideDVal=procdat;
ch.chFinalVol=ch.chVol=volrange(ch.chVol-ch.chFineVolSlideDVal);
break;
case 50:
patdelay=procdat;
break;
}
}
}
for (i=0; i<nchan; i++)
{
channel &ch=channels[i];
switch (ch.chVCommand)
{
case 6:
if (tick0)
break;
ch.chFinalVol=ch.chVol=volrange(ch.chVol-ch.chVVolPanSlideVal);
break;
case 7:
if (tick0)
break;
ch.chFinalVol=ch.chVol=volrange(ch.chVol+ch.chVVolPanSlideVal);
break;
case 11:
switch (ch.chVibType)
{
case 0:
ch.chFinalPitch=freqrange((( sintab[ch.chVibPos] *ch.chVibDep)>>8)+ch.chFinalPitch);
break;
case 1:
ch.chFinalPitch=freqrange((( (ch.chVibPos-0x80) *ch.chVibDep)>>4)+ch.chFinalPitch);
break;
case 2:
ch.chFinalPitch=freqrange((( ((ch.chVibPos&0x80)-0x40) *ch.chVibDep)>>3)+ch.chFinalPitch);
break;
}
if (!tick0)
ch.chVibPos+=ch.chVibRate;
break;
case 13:
if (tick0)
break;
ch.chFinalPan=ch.chPan=panrange(ch.chPan-ch.chVVolPanSlideVal);
break;
case 14:
if (tick0)
break;
ch.chFinalPan=ch.chPan=panrange(ch.chPan+ch.chVVolPanSlideVal);
break;
case 15:
if (!tick0)
if (ch.chPitch<ch.chPortaToPitch)
{
ch.chPitch+=ch.chPortaToVal;
if (ch.chPitch>ch.chPortaToPitch)
ch.chPitch=ch.chPortaToPitch;
}
else
{
ch.chPitch-=ch.chPortaToVal;
if (ch.chPitch<ch.chPortaToPitch)
ch.chPitch=ch.chPortaToPitch;
}
if (ch.chGlissando)
{
if (linearfreq)
ch.chFinalPitch=((ch.chPitch+ch.chCurNormNote+0x80)&~0xFF)-ch.chCurNormNote;
else
ch.chFinalPitch=mcpGetFreq6848(((mcpGetNote6848(ch.chPitch)+ch.chCurNormNote+0x80)&~0xFF)-ch.chCurNormNote);
}
else
ch.chFinalPitch=ch.chPitch;
break;
}
switch (ch.chCommand)
{
case 0:
if (linearfreq)
ch.chFinalPitch=freqrange(ch.chFinalPitch-(ch.chArpNotes[ch.chArpPos]<<8));
else
ch.chFinalPitch=freqrange((ch.chFinalPitch*notetab[ch.chArpNotes[ch.chArpPos]])>>15);
ch.chArpPos++;
if (ch.chArpPos==3)
ch.chArpPos=0;
break;
case 1:
if (tick0)
break;
ch.chFinalPitch=ch.chPitch=freqrange(ch.chPitch-ch.chPortaUVal);
break;
case 2:
if (tick0)
break;
ch.chFinalPitch=ch.chPitch=freqrange(ch.chPitch+ch.chPortaDVal);
break;
case 3:
if (!tick0)
if (ch.chPitch<ch.chPortaToPitch)
{
ch.chPitch+=ch.chPortaToVal;
if (ch.chPitch>ch.chPortaToPitch)
ch.chPitch=ch.chPortaToPitch;
}
else
{
ch.chPitch-=ch.chPortaToVal;
if (ch.chPitch<ch.chPortaToPitch)
ch.chPitch=ch.chPortaToPitch;
}
if (ch.chGlissando)
{
if (linearfreq)
ch.chFinalPitch=((ch.chPitch+ch.chCurNormNote+0x80)&~0xFF)-ch.chCurNormNote;
else
ch.chFinalPitch=mcpGetFreq6848(((mcpGetNote6848(ch.chPitch)+ch.chCurNormNote+0x80)&~0xFF)-ch.chCurNormNote);
}
else
ch.chFinalPitch=ch.chPitch;
break;
case 4:
switch (ch.chVibType)
{
case 0:
ch.chFinalPitch=freqrange((( sintab[ch.chVibPos] *ch.chVibDep)>>8)+ch.chFinalPitch);
break;
case 1:
ch.chFinalPitch=freqrange((( (ch.chVibPos-0x80) *ch.chVibDep)>>4)+ch.chFinalPitch);
break;
case 2:
ch.chFinalPitch=freqrange((( ((ch.chVibPos&0x80)-0x40) *ch.chVibDep)>>3)+ch.chFinalPitch);
break;
}
if (!tick0)
ch.chVibPos+=ch.chVibRate;
break;
case 5:
if (!tick0)
if (ch.chPitch<ch.chPortaToPitch)
{
ch.chPitch+=ch.chPortaToVal;
if (ch.chPitch>ch.chPortaToPitch)
ch.chPitch=ch.chPortaToPitch;
}
else
{
ch.chPitch-=ch.chPortaToVal;
if (ch.chPitch<ch.chPortaToPitch)
ch.chPitch=ch.chPortaToPitch;
}
if (ch.chGlissando)
{
if (linearfreq)
ch.chFinalPitch=((ch.chPitch+ch.chCurNormNote+0x80)&~0xFF)-ch.chCurNormNote;
else
ch.chFinalPitch=mcpGetFreq6848(((mcpGetNote6848(ch.chPitch)+ch.chCurNormNote+0x80)&~0xFF)-ch.chCurNormNote);
}
else
ch.chFinalPitch=ch.chPitch;
if (tick0)
break;
ch.chFinalVol=ch.chVol=volrange(ch.chVol+((ch.chVolSlideVal&0xF0)?(ch.chVolSlideVal>>4):-(ch.chVolSlideVal&0xF)));
break;
case 6:
switch (ch.chVibType)
{
case 0:
ch.chFinalPitch=freqrange((( sintab[ch.chVibPos] *ch.chVibDep)>>8)+ch.chFinalPitch);
break;
case 1:
ch.chFinalPitch=freqrange((( (ch.chVibPos-0x80) *ch.chVibDep)>>4)+ch.chFinalPitch);
break;
case 2:
ch.chFinalPitch=freqrange((( ((ch.chVibPos&0x80)-0x40) *ch.chVibDep)>>3)+ch.chFinalPitch);
break;
}
if (!tick0)
ch.chVibPos+=ch.chVibRate;
if (tick0)
break;
ch.chFinalVol=ch.chVol=volrange(ch.chVol+((ch.chVolSlideVal&0xF0)?(ch.chVolSlideVal>>4):-(ch.chVolSlideVal&0xF)));
break;
case 7:
switch (ch.chTremType)
{
case 0:
ch.chFinalVol+=(( sintab[ch.chTremPos] *ch.chTremDep)>>11);
break;
case 1:
ch.chFinalVol+=(( (ch.chTremPos-0x80) *ch.chTremDep)>>7);
break;
case 2:
ch.chFinalVol+=(( ((ch.chTremPos&0x80)-0x40) *ch.chTremDep)>>6);
break;
}
ch.chFinalVol=volrange(ch.chFinalVol);
if (!tick0)
ch.chTremPos+=ch.chTremRate;
break;
case 10:
if (tick0)
break;
ch.chFinalVol=ch.chVol=volrange(ch.chVol+((ch.chVolSlideVal&0xF0)?(ch.chVolSlideVal>>4):-(ch.chVolSlideVal&0xF)));
break;
case 17:
if (tick0)
break;
if (ch.chGVolSlideVal&0xF0)
globalvol=volrange(globalvol+(ch.chGVolSlideVal>>4));
else
globalvol=volrange(globalvol-(ch.chGVolSlideVal&0xF));
break;
case 20:
if (tick0)
break;
if (curtick==ch.chActionTick)
{
ch.chSustain=0;
if (ch.cursamp&&(ch.cursamp->volenv>=nenv))
ch.chFadeVol=0;
}
break;
case 25:
if (tick0)
break;
ch.chFinalPan=ch.chPan=panrange(ch.chPan+((ch.chPanSlideVal&0xF0)?(ch.chPanSlideVal>>4):-(ch.chPanSlideVal&0xF)));
break;
case 27:
if (ch.chMRetrigPos++!=ch.chMRetrigLen)
break;
ch.chMRetrigPos=0;
ch.nextpos=0;
switch (ch.chMRetrigAct)
{
case 0: case 8: break;
case 1: case 2: case 3: case 4: case 5:
ch.chVol=ch.chVol-(1<<(ch.chMRetrigAct-1));
break;
case 9: case 10: case 11: case 12: case 13:
ch.chVol=ch.chVol+(1<<(ch.chMRetrigAct-9));
break;
case 6: ch.chVol=(ch.chVol*5)>>3; break;
case 14: ch.chVol=(ch.chVol*3)>>1; break;
case 7: ch.chVol>>=1; break;
case 15: ch.chVol<<=1; break;
}
ch.chFinalVol=ch.chVol=volrange(ch.chVol);
break;
case 29:
if (ch.chTremorPos>=ch.chTremorOff)
ch.chFinalVol=0;
if (tick0)
break;
ch.chTremorPos++;
if (ch.chTremorPos==ch.chTremorLen)
ch.chTremorPos=0;
break;
case 45:
if (!ch.chActionTick)
break;
if (!(curtick%ch.chActionTick))
ch.nextpos=0;
break;
case 48:
if (tick0)
break;
if (curtick==ch.chActionTick)
ch.chFinalVol=ch.chVol=0;
break;
case 49:
if (tick0)
break;
if (curtick!=ch.chActionTick)
break;
notedelayed=1;
procnot=ch.chDelayNote;
procins=ch.chCurIns;
proccmd=0;
procdat=0;
procvol=0;
PlayNote(ch);
break;
}
if (!ch.cursamp)
{
mcpSet(i, mcpCStatus, 0);
continue;
}
sample &sm=*ch.cursamp;
int vol=(ch.chFinalVol*globalvol)>>4;
int pan=ch.chFinalPan-128;
if (!ch.chSustain)
{
vol=(vol*ch.chFadeVol)>>15;
if (ch.chFadeVol>=sm.volfade)
ch.chFadeVol-=sm.volfade;
else
ch.chFadeVol=0;
}
if (sm.volenv<nenv)
{
const envelope &env=envelopes[sm.volenv];
vol=(env.env[ch.chVolEnvPos]*vol)>>8;
if (ch.chVolEnvPos<env.len)
ch.chVolEnvPos++;
if (ch.chSustain&&(env.type&mpEnvSLoop))
{
if (ch.chVolEnvPos==env.sloope)
ch.chVolEnvPos=env.sloops;
}
else
if (env.type&mpEnvLoop)
{
if (ch.chVolEnvPos==env.loope)
ch.chVolEnvPos=env.loops;
}
}
if (sm.panenv<nenv)
{
const envelope &env=envelopes[sm.panenv];
pan+=((env.env[ch.chPanEnvPos]-128)*(128-((pan<0)?-pan:pan)))>>7;
if (ch.chPanEnvPos<env.len)
ch.chPanEnvPos++;
if (ch.chSustain&&(env.type&mpEnvSLoop))
{
if (ch.chPanEnvPos==env.sloope)
ch.chPanEnvPos=env.sloops;
}
else
if (env.type&mpEnvLoop)
{
if (ch.chPanEnvPos==env.loope)
ch.chPanEnvPos=env.loops;
}
}
if (sm.vibrate&&sm.vibdepth)
{
int dep=0;
switch (sm.vibtype)
{
case 0:
dep=(sintab[(ch.chAVibPos>>8)&0xFF]*sm.vibdepth)>>11;
break;
case 1:
dep=(ch.chAVibPos&0x8000)?-sm.vibdepth:sm.vibdepth;
break;
case 2:
dep=(sm.vibdepth*(32768-ch.chAVibPos))>>14;
break;
case 3:
dep=(sm.vibdepth*(ch.chAVibPos-32768))>>14;
break;
}
ch.chAVibSwpPos+=sm.vibsweep;
if (ch.chAVibSwpPos>0x10000)
ch.chAVibSwpPos=0x10000;
dep=(dep*(int)ch.chAVibSwpPos)>>16;
ch.chFinalPitch-=dep;
ch.chAVibPos+=sm.vibrate;
}
if (ch.nextstop)
mcpSet(i, mcpCStatus, 0);
if (ch.nextsamp!=-1)
mcpSet(i, mcpCInstrument, ch.nextsamp);
if (ch.nextpos!=-1)
{
mcpSet(i, mcpCPosition, ch.nextpos);
mcpSet(i, mcpCStatus, 1);
}
if (linearfreq)
mcpSet(i, mcpCPitch, -ch.chFinalPitch);
else
mcpSet(i, mcpCPitch6848, ch.chFinalPitch);
mcpSet(i, mcpCVolume, (looping||!looped)?vol:0);
mcpSet(i, mcpCPanning, pan);
mcpSet(i, mcpCMute, mutech[i]);
}
}
int xmpChanActive(int ch)
{
return mcpGet(ch, mcpCStatus)&&channels[ch].cursamp&&channels[ch].chVol&&channels[ch].chFadeVol;
}
int xmpGetChanIns(int ch)
{
return channels[ch].chCurIns;
}
int xmpGetChanSamp(int ch)
{
if (!channels[ch].cursamp)
return 0xFFFF;
return channels[ch].cursamp-samples;
}
int xmpGetDotsData(int ch, int &smp, int &frq, int &voll, int &volr, int &sus)
{
if (!mcpGet(ch, mcpCStatus))
return 0;
channel &c=channels[ch];
if (!c.cursamp||!c.chVol||!c.chFadeVol)
return 0;
smp=c.cursamp-samples;
if (linearfreq)
frq=60*256+c.cursamp->normnote-freqrange(c.chFinalPitch);
else
frq=60*256+c.cursamp->normnote+mcpGetNote8363(6848*8363/freqrange(c.chFinalPitch));
mcpGetRealVolume(ch, voll, volr);
sus=c.chSustain;
return 1;
}
void xmpGetRealVolume(int ch, int &voll, int &volr)
{
mcpGetRealVolume(ch, voll, volr);
}
unsigned short xmpGetPos()
{
return (curord<<8)|currow;
}
void xmpSetPos(int ord, int row)
{
if (row<0)
ord--;
if (ord>=nord)
ord=0;
if (ord<0)
{
ord=0;
row=0;
}
if (row>=patlens[orders[ord]])
{
ord++;
row=0;
}
if (ord>=nord)
ord=0;
if (row<0)
{
row+=patlens[orders[ord]];
if (row<0)
row=0;
}
int i;
for (i=0; i<nchan; i++)
mcpSet(i, mcpCReset, 0);
jumptoord=ord;
jumptorow=row;
curtick=curtempo;
curord=ord;
currow=row;
usersetpos=1;
}
int xmpGetLChanSample(int ch, short *b, int len, int rate)
{
return mcpGetChanSample(ch, b, len, rate);
}
void xmpMute(int i, int m)
{
mutech[i]=m;
}
int xmpLoop()
{
return looped;
}
void xmpSetLoop(int x)
{
looping=x;
}
int xmpPlayModule(xmodule &m)
{
int i;
mcpLoadSamples(m.sampleinfos, m.nsampi);
memset(channels, 0, sizeof(channels));
globalvol=0x40;
jumptorow=0;
jumptoord=0;
curord=0;
currow=0;
ninst=m.ninst;
nord=m.nord;
nsamp=m.nsamp;
instruments=m.instruments;
envelopes=m.envelopes;
samples=m.samples;
patterns=m.patterns;
orders=m.orders;
patlens=m.patlens;
linearfreq=m.linearfreq;
nchan=m.nchan;
loopord=m.loopord;
nenv=m.nenv;
looped=0;
curtempo=m.initempo;
curtick=m.initempo-1;
for (i=0; i<nchan; i++)
{
channels[i].chPan=((i*3)&2)?0xFF:0x00;
mutech[i]=0;
}
firstspeed=256*2*m.inibpm/5;
if (!mcpOpenPlayer(nchan, xmpPlayTick))
return 0;
if (nchan!=mcpNChan)
{
mcpClosePlayer();
return 0;
}
return 1;
}
void xmpStopModule()
{
mcpClosePlayer();
}
int xmpLoadModule(xmodule &m, binfile &file)
{
m.envelopes=0;
m.samples=0;
m.instruments=0;
m.sampleinfos=0;
m.patlens=0;
m.patterns=0;
m.orders=0;
struct
{
char sig[17];
char name[20];
char eof;
char tracker[20];
unsigned short ver;
unsigned long hdrsize;
} head1;
struct
{
unsigned short nord;
unsigned short loopord;
unsigned short nchan;
unsigned short npat;
unsigned short ninst;
unsigned short freqtab;
unsigned short tempo;
unsigned short bpm;
unsigned char ord[256];
} head2;
file.read(&head1, sizeof(head1));
if (memcmp(head1.sig, "Extended Module: ", 17))
return errFormStruc;
if (head1.eof!=26)
return errFormStruc;
if (head1.ver<0x104)
return errFormOldVer;
file.read(&head2, sizeof(head2));
file.seekcur(head1.hdrsize-4-sizeof(head2));
if (!head2.ninst)
return errFormMiss;
memcpy(m.name, head1.name, 20);
m.name[20]=0;
m.linearfreq=!!(head2.freqtab&1);
m.nchan=head2.nchan;
m.ninst=head2.ninst;
m.nenv=head2.ninst*2;
m.npat=head2.npat+1;
m.nord=head2.nord;
m.loopord=head2.loopord;
m.inibpm=head2.bpm;
m.initempo=head2.tempo;
m.orders=new unsigned short [head2.nord];
m.patterns=(unsigned char (**)[5])new void *[head2.npat+1];
m.patlens=new unsigned short [head2.npat+1];
m.instruments=new instrument [head2.ninst];
m.envelopes=new envelope [head2.ninst*2];
sampleinfo **smps=new sampleinfo *[head2.ninst];
sample **msmps=new sample *[head2.ninst];
int *instsmpnum=new int [head2.ninst];
if (!smps||!msmps||!instsmpnum||!m.instruments||!m.envelopes||!m.patterns||!m.orders||!m.patlens)
return errAllocMem;
memset(m.patterns, 0, (head2.npat+1)*sizeof(void*));
memset(m.envelopes, 0, (head2.ninst*2)*sizeof(envelope));
int i,j,k;
for (i=0; i<head2.nord; i++)
m.orders[i]=(head2.ord[i]<head2.npat)?head2.ord[i]:head2.npat;
m.patlens[head2.npat]=64;
m.patterns[head2.npat]=new unsigned char [64*head2.nchan][5];
if (!m.patterns[head2.npat])
return errAllocMem;
memset(m.patterns[head2.npat], 0, 64*5*head2.nchan);
for (i=0; i<head2.npat; i++)
{
struct
{
unsigned long len;
unsigned char ptype;
unsigned short rows;
unsigned short patdata;
} pathead;
file.read(&pathead, sizeof(pathead));
file.seekcur(pathead.len-sizeof(pathead));
m.patlens[i]=pathead.rows;
m.patterns[i]=new unsigned char [pathead.rows*head2.nchan][5];
if (!m.patterns[i])
return errAllocMem;
memset(m.patterns[i], 0, pathead.rows*head2.nchan*5);
if (!pathead.patdata)
continue;
unsigned char *pbuf=new unsigned char [pathead.patdata];
if (!pbuf)
return errAllocMem;
file.read(pbuf, pathead.patdata);
unsigned char *pbp=pbuf;
unsigned char *cur=(unsigned char*)(m.patterns[i]);
for (j=0; j<(pathead.rows*head2.nchan); j++)
{
unsigned char pack=(*pbp&0x80)?(*pbp++):0x1F;
for (k=0; k<5; k++)
{
*cur++=(pack&1)?*pbp++:0;
pack>>=1;
}
if (cur[-2]==0xE)
{
cur[-2]=36+(cur[-1]>>4);
cur[-1]&=0xF;
}
}
delete pbuf;
}
m.nsampi=0;
m.nsamp=0;
for (i=0; i<m.ninst; i++)
{
instrument &ip=m.instruments[i];
envelope *env=m.envelopes+2*i;
smps[i]=0;
msmps[i]=0;
struct
{
unsigned long size;
char name[22];
char type;
unsigned short samp;
} ins1;
file.read(&ins1, sizeof(ins1));
memcpy(ip.name, ins1.name, 22);
ip.name[22]=0;
memset(ip.samples, -1, 256);
instsmpnum[i]=ins1.samp;
if (!ins1.samp)
{
file.seekcur(ins1.size-sizeof(ins1));
continue;
}
struct
{
unsigned long shsize;
unsigned char snum[96];
unsigned short venv[12][2];
unsigned short penv[12][2];
unsigned char vnum, pnum;
unsigned char vsustain, vloops, vloope, psustain, ploops, ploope;
unsigned char vtype, ptype;
unsigned char vibtype, vibsweep, vibdepth, vibrate;
unsigned short volfade;
unsigned short res;
} ins2;
file.read(&ins2, sizeof(ins2));
file.seekcur(ins1.size-sizeof(ins1)-sizeof(ins2));
smps[i]=new sampleinfo[ins1.samp];
msmps[i]=new sample[ins1.samp];
if (!smps[i]||!msmps[i])
return errAllocMem;
memset(msmps[i], 0, sizeof(**msmps)*ins1.samp);
memset(smps[i], 0, sizeof(**smps)*ins1.samp);
memset(ip.samples, 0xFF, 128*2);
for (j=0; j<96; j++)
if (ins2.snum[j]<ins1.samp)
ip.samples[j]=m.nsamp+ins2.snum[j];
unsigned short volfade=0xFFFF;
volfade=ins2.volfade;
if (ins2.vtype&1)
{
env[0].speed=0;
env[0].type=0;
env[0].env=new unsigned char[ins2.venv[ins2.vnum-1][0]+1];
if (!env[0].env)
return errAllocMem;
short k, p=0, h=ins2.venv[0][1]*4;
for (j=1; j<ins2.vnum; j++)
{
short l=ins2.venv[j][0]-p;
short dh=ins2.venv[j][1]*4-h;
for (k=0; k<l; k++)
{
short cv=h+dh*k/l;
env[0].env[p++]=(cv>255)?255:cv;
}
h+=dh;
}
env[0].len=p;
env[0].env[p]=(h>255)?255:h;
if (ins2.vtype&2)
{
env[0].type|=mpEnvSLoop;
if (!(ins2.vtype&4)||(ins2.vsustain<=ins2.vloope))
{
env[0].sloops=ins2.venv[ins2.vsustain][0];
env[0].sloope=ins2.venv[ins2.vsustain][0]+1;
}
else
{
env[0].sloops=ins2.venv[ins2.vloops][0];
env[0].sloope=ins2.venv[ins2.vloope][0];
}
}
if (ins2.vtype&4)
{
if ((ins2.vtype&2)&&(ins2.vsustain==ins2.vloope))
{
env[0].type|=mpEnvSLoop;
env[0].sloops=ins2.venv[ins2.vloops][0];
env[0].sloope=ins2.venv[ins2.vloope][0];
}
else
{
env[0].type|=mpEnvLoop;
env[0].loops=ins2.venv[ins2.vloops][0];
env[0].loope=ins2.venv[ins2.vloope][0];
}
}
}
if (ins2.ptype&1)
{
env[1].speed=0;
env[1].type=0;
env[1].env=new unsigned char[ins2.penv[ins2.pnum-1][0]+1];
if (!env[1].env)
return errAllocMem;
short k, p=0, h=ins2.penv[0][1]*4;
for (j=1; j<ins2.pnum; j++)
{
short l=ins2.penv[j][0]-p;
short dh=ins2.penv[j][1]*4-h;
for (k=0; k<l; k++)
{
short cv=h+dh*k/l;
env[1].env[p++]=(cv>255)?255:cv;
}
h+=dh;
}
env[1].len=p;
env[1].env[p]=(h>255)?255:h;
if (ins2.ptype&2)
{
env[1].type|=mpEnvSLoop;
if (!(ins2.ptype&4)||(ins2.psustain<=ins2.ploope))
{
env[1].sloops=ins2.penv[ins2.psustain][0];
env[1].sloope=ins2.penv[ins2.psustain][0]+1;
}
else
{
env[1].sloops=ins2.penv[ins2.ploops][0];
env[1].sloope=ins2.penv[ins2.ploope][0];
}
}
if (ins2.ptype&4)
{
if ((ins2.ptype&2)&&(ins2.psustain==ins2.ploope))
{
env[1].type|=mpEnvSLoop;
env[1].sloops=ins2.penv[ins2.ploops][0];
env[1].sloope=ins2.penv[ins2.ploope][0];
}
else
{
env[1].type|=mpEnvLoop;
env[1].loops=ins2.penv[ins2.ploops][0];
env[1].loope=ins2.penv[ins2.ploope][0];
}
}
}
for (j=0; j<ins1.samp; j++)
{
struct
{
unsigned long samplen;
unsigned long loopstart;
unsigned long looplen;
unsigned char vol;
signed char finetune;
unsigned char type;
unsigned char pan;
signed char relnote;
unsigned char res;
unsigned char name[22];
} samp;
file.read(&samp, sizeof (samp));
file.seekcur(ins2.shsize-sizeof(samp));
if (samp.type&16)
{
samp.samplen>>=1;
samp.loopstart>>=1;
samp.looplen>>=1;
}
sample &sp=msmps[i][j];
memcpy(sp.name, samp.name, 22);
sp.name[22]=0;
sp.handle=0xFFFF;
sp.normnote=-samp.relnote*256-samp.finetune*2;
sp.stdvol=(samp.vol>0x3F)?0xFF:(samp.vol<<2);
sp.stdpan=samp.pan;
sp.opt=0;
sp.volfade=volfade;
sp.vibtype=ins2.vibtype;
sp.vibdepth=ins2.vibdepth<<2;
sp.vibspeed=0;
sp.vibrate=ins2.vibrate<<8;
sp.vibsweep=0xFFFF/(ins2.vibsweep+1);
sp.volenv=env[0].env?(2*i+0):0xFFFF;
sp.panenv=env[1].env?(2*i+1):0xFFFF;
sp.pchenv=0xFFFF;
sampleinfo &sip=smps[i][j];
sip.length=samp.samplen;
sip.loopstart=samp.loopstart;
sip.loopend=samp.loopstart+samp.looplen;
sip.samprate=8363;
sip.type=mcpSampDelta|((samp.type&16)?mcpSamp16Bit:0)|((samp.type&3)?(((samp.type&3)==2)?(mcpSampLoop|mcpSampBiDi):mcpSampLoop):0);
}
for (j=0; j<ins1.samp; j++)
{
sample &sp=msmps[i][j];
sampleinfo &sip=smps[i][j];
unsigned long l=sip.length<<(!!(sip.type&mcpSamp16Bit));
if (!l)
continue;
sip.ptr=new char [l+16];
if (!sip.ptr)
return errAllocMem;
file.read(sip.ptr, l);
sp.handle=m.nsampi++;
}
m.nsamp+=ins1.samp;
}
m.samples=new sample [m.nsamp];
m.sampleinfos=new sampleinfo [m.nsampi];
if (!m.samples||!m.sampleinfos)
return errAllocMem;
m.nsampi=0;
m.nsamp=0;
for (i=0; i<m.ninst; i++)
{
for (j=0; j<instsmpnum[i]; j++)
{
m.samples[m.nsamp++]=msmps[i][j];
if (smps[i][j].ptr)
m.sampleinfos[m.nsampi++]=smps[i][j];
}
delete smps[i];
delete msmps[i];
}
delete smps;
delete msmps;
delete instsmpnum;
return errOk;
}
void xmpFreeModule(xmodule &m)
{
int i;
if (m.sampleinfos)
for (i=0; i<m.nsampi; i++)
delete m.sampleinfos[i].ptr;
delete m.sampleinfos;
delete m.samples;
if (m.envelopes)
for (i=0; i<m.nenv; i++)
delete m.envelopes[i].env;
delete m.envelopes;
delete m.instruments;
if (m.patterns)
for (i=0; i<m.npat; i++)
delete m.patterns[i];
delete m.patterns;
delete m.patlens;
delete m.orders;
}
static unsigned short modnotetab[85]=
{
0xCFF, 0xC44, 0xB94, 0xAED, 0xA50, 0x9BC, 0x930, 0x8AC, 0x830, 0x7BA, 0x74B, 0x6E2,
0x67F, 0x622, 0x5CA, 0x577, 0x528, 0x4DE, 0x498, 0x456, 0x418, 0x3DD, 0x3A5, 0x371,
0x340, 0x311, 0x2E5, 0x2BB, 0x294, 0x26F, 0x24C, 0x22B, 0x20C, 0x1EE, 0x1D3, 0x1B9,
0x1A0, 0x188, 0x172, 0x15E, 0x14A, 0x138, 0x126, 0x116, 0x106, 0x0F7, 0x0E9, 0x0DC,
0x0D0, 0x0C4, 0x0B9, 0x0AF, 0x0A5, 0x09C, 0x093, 0x08B, 0x083, 0x07C, 0x075, 0x06E,
0x068, 0x062, 0x05D, 0x057, 0x053, 0x04E, 0x04A, 0x045, 0x041, 0x03E, 0x03A, 0x037,
0x034, 0x031, 0x02E, 0x02C, 0x029, 0x027, 0x025, 0x023, 0x021, 0x01F, 0x01D, 0x01C, 0
};
static inline unsigned long swapb2(unsigned short a)
{
return ((a&0xFF)<<9)|((a&0xFF00)>>7);
}
static int loadmod(xmodule &m, binfile &file, int chan, int sig)
{
m.envelopes=0;
m.samples=0;
m.instruments=0;
m.sampleinfos=0;
m.patlens=0;
m.patterns=0;
m.orders=0;
m.nenv=0;
m.linearfreq=0;
unsigned long l=file[1080].getl();
m.ninst=31;
m.nchan=0;
switch (l)
{
case 0x2E4B2E4D: // M.K.
case 0x214B214D: // M!K!
case 0x34544C46: // FLT4
m.nchan=4;
break;
case 0x2E542E4E: // N.T.
m.nchan=4;
m.ninst=15;
break;
case 0x31384443: m.nchan=8; break; // CD81
case 0x315A4454: m.nchan=1; break; // TDZ1
case 0x325A4454: m.nchan=2; break;
case 0x335A4454: m.nchan=3; break;
case 0x345A4454: m.nchan=4; break;
case 0x355A4454: m.nchan=5; break;
case 0x365A4454: m.nchan=6; break;
case 0x375A4454: m.nchan=7; break;
case 0x385A4454: m.nchan=8; break;
case 0x395A4454: m.nchan=9; break;
case 0x4E484331: m.nchan=1; break; // 1CHN...
case 0x4E484332: m.nchan=2; break;
case 0x4E484333: m.nchan=3; break;
case 0x4E484334: m.nchan=4; break;
case 0x4E484335: m.nchan=5; break;
case 0x4E484336: m.nchan=6; break;
case 0x4E484337: m.nchan=7; break;
case 0x4E484338: m.nchan=8; break;
case 0x4E484339: m.nchan=9; break;
case 0x48433031: m.nchan=10; break; // 10CH...
case 0x48433131: m.nchan=11; break;
case 0x48433231: m.nchan=12; break;
case 0x48433331: m.nchan=13; break;
case 0x48433431: m.nchan=14; break;
case 0x48433531: m.nchan=15; break;
case 0x48433631: m.nchan=16; break;
case 0x48433731: m.nchan=17; break;
case 0x48433831: m.nchan=18; break;
case 0x48433931: m.nchan=19; break;
case 0x48433032: m.nchan=20; break;
case 0x48433132: m.nchan=21; break;
case 0x48433232: m.nchan=22; break;
case 0x48433332: m.nchan=23; break;
case 0x48433432: m.nchan=24; break;
case 0x48433532: m.nchan=25; break;
case 0x48433632: m.nchan=26; break;
case 0x48433732: m.nchan=27; break;
case 0x48433832: m.nchan=28; break;
case 0x48433932: m.nchan=29; break;
case 0x48433033: m.nchan=30; break;
case 0x48433133: m.nchan=31; break;
case 0x48433233: m.nchan=32; break;
case 0x38544C46: // FLT8
return errFormSupp;
m.nchan=8;
break;
default:
if (sig==1)
return errFormSig;
m.ninst=(sig==2)?31:15;
break;
}
if (chan)
m.nchan=chan;
if (!m.nchan)
return errFormSig;
m.nsampi=m.ninst;
m.nsamp=m.ninst;
m.instruments=new instrument[m.ninst];
m.samples=new sample[m.ninst];
m.sampleinfos=new sampleinfo[m.ninst];
if (!m.instruments||!m.samples||!m.sampleinfos)
return errAllocMem;
memset(m.samples, 0, sizeof(*m.samples)*m.ninst);
memset(m.sampleinfos, 0, sizeof(*m.sampleinfos)*m.ninst);
file[0].read(m.name, 20);
m.name[20]=0;
int i;
for (i=0; i<m.ninst; i++)
{
struct
{
char name[22];
unsigned short length;
signed char finetune;
unsigned char volume;
unsigned short loopstart;
unsigned short looplength;
} mi;
file.read(&mi, sizeof(mi));
unsigned long length=swapb2(mi.length);
unsigned long loopstart=swapb2(mi.loopstart);
unsigned long looplength=swapb2(mi.looplength);
if (length<4)
length=0;
if (looplength<4)
looplength=0;
if (!looplength||(loopstart>=length))
looplength=0;
else
if ((loopstart+looplength)>length)
looplength=length-loopstart;
if (mi.finetune&0x08)
mi.finetune|=0xF0;
instrument &ip=m.instruments[i];
sample &sp=m.samples[i];
sampleinfo &sip=m.sampleinfos[i];
memcpy(ip.name, mi.name, 22);
int j;
for (j=21; j>=0; j--)
if (ip.name[j]>=0x20)
break;
ip.name[j+1]=0;
memset(ip.samples, -1, 256);
*sp.name=0;
sp.handle=0xFFFF;
sp.stdpan=-1;
sp.opt=0;
sp.normnote=-mi.finetune*32;
sp.stdvol=(mi.volume>0x3F)?0xFF:(mi.volume<<2);
sp.volenv=0xFFFF;
sp.panenv=0xFFFF;
sp.pchenv=0xFFFF;
sp.volfade=0;
sp.vibspeed=0;
sp.vibrate=0;
if (!length)
continue;
for (j=0; j<128; j++)
ip.samples[j]=i;
sp.handle=i;
sip.length=length;
sip.loopstart=loopstart;
sip.loopend=loopstart+looplength;
sip.samprate=8363;
sip.type=looplength?mcpSampLoop:0;
}
unsigned char orders[128];
unsigned char ordn=file.getc();
unsigned char loopp=file.getc();
file.read(orders, 128);
if (loopp>=ordn)
loopp=0;
short pn=0;
short t;
for (t=0; t<128; t++)
if (pn<orders[t])
pn=orders[t];
pn++;
m.nord=ordn;
m.loopord=loopp;
m.npat=pn;
m.initempo=6;
m.inibpm=125;
if (sig)
file.getl();
m.orders=new unsigned short [m.nord];
m.patlens=new unsigned short [m.npat];
m.patterns=(unsigned char (**)[5])new void *[m.npat];
unsigned char *temppat=new unsigned char [4*64*m.nchan];
if (!m.orders||!m.patlens||!m.patterns||!temppat)
return errAllocMem;
for (i=0; i<m.nord; i++)
m.orders[i]=orders[i];
memset(m.patterns, 0, sizeof(*m.patterns)*m.npat);
for (i=0; i<m.npat; i++)
{
m.patlens[i]=64;
m.patterns[i]=new unsigned char [64*m.nchan][5];
if (!m.patterns[i])
return errAllocMem;
}
for (i=0; i<pn; i++)
{
unsigned char *dp=(unsigned char *)(m.patterns[i]);
unsigned char *sp=temppat;
file.read(temppat, 256*m.nchan);
int j;
for (j=0; j<(64*m.nchan); j++)
{
unsigned short nvalue=((short)(sp[0]&0xF)<<8)+sp[1];
dp[0]=0;
if (nvalue)
{
int k;
for (k=0; k<85; k++)
if (modnotetab[k]<=nvalue)
break;
dp[0]=k+13;
}
dp[1]=(sp[2]>>4)|(sp[0]&0x10);
dp[2]=0;
dp[3]=sp[2]&0xF;
dp[4]=sp[3];
if (dp[3]==0xE)
{
dp[3]=36+(dp[4]>>4);
dp[4]&=0xF;
}
if (!dp[4])
switch (dp[3])
{
case 10: case 46: case 47:
dp[3]=0;
}
sp+=4;
dp+=5;
}
}
delete temppat;
for (i=0; i<m.ninst; i++)
{
instrument &ip=m.instruments[i];
sample &sp=m.samples[i];
sampleinfo &sip=m.sampleinfos[i];
if (sp.handle==0xFFFF)
continue;
sip.ptr=new unsigned char[sip.length+8];
if (!sip.ptr)
return errAllocMem;
memset(sip.ptr, 0, sip.length);
file.read(sip.ptr, sip.length);
sp.handle=i;
}
return errOk;
}
int xmpLoadMOD(xmodule &m, binfile &file)
{
return loadmod(m, file, 0, 1);
}
int xmpLoadM31(xmodule &m, binfile &file)
{
return loadmod(m, file, 4, 2);
}
int xmpLoadM15(xmodule &m, binfile &file)
{
return loadmod(m, file, 4, 0);
}
int xmpLoadWOW(xmodule &m, binfile &file)
{
return loadmod(m, file, 8, 1);
}